﻿#include "com_log.h"
#include <errno.h>
#include <pthread.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <time.h>

typedef struct {
    const char*   name_prefix;
    com_log_level level;
} module_info;

static FILE* log_fp = NULL;

static module_info _infos[] = {
    {"net",          COM_LOG_INFO },
    { "init",        COM_LOG_INFO },

    { "ioctl",       COM_LOG_INFO },

    { "sock-com",    COM_LOG_INFO },
    { "sock-dat",    COM_LOG_DEBUG},

    { "USB-com",     COM_LOG_INFO },
    { "USB-dat",     COM_LOG_DEBUG},

    { "UART-com",    COM_LOG_INFO },

    { "hotplug-com", COM_LOG_INFO },
    { "hotplug-dat", COM_LOG_DEBUG},

    { "cb-com",      COM_LOG_INFO },
    { "cb-dat",      COM_LOG_DEBUG},

    { "base-dat",    COM_LOG_INFO },
    { "cmdline",     COM_LOG_INFO },
};

static com_log_level pri_level = COM_LOG_INFO;

static int _com_vprintf(const char* fun, const char* module, const char* level, const char* fmt, va_list va)
{
#define MAX_BUF (4096)
    char buff[MAX_BUF];

    struct timespec spec;
    /*
    timespec_get(&spec, TIME_UTC);
    **/
    clock_gettime(CLOCK_REALTIME, &spec);

    int len = sprintf(buff,
                      "[%d.%06d] [%p] [%s] [%s] %s:",
                      (int)spec.tv_sec,
                      (int)(spec.tv_nsec / 1000),
#ifdef WIN32
                      pthread_self().p,
#else
                      (void*)pthread_self(),
#endif
                      level,
                      module,
                      fun);

    len += vsnprintf(buff + len, MAX_BUF - len, fmt, va);
    len += sprintf(buff + len, "\n");

    printf("%s", buff);
    if (log_fp) {
        int len = strlen(buff);
        fwrite(buff, sizeof(char), len, log_fp);
        fflush(log_fp);
    }

    return len;
}

void com_log_init(char* file)
{
    log_fp = fopen(file, "w");
    if (!log_fp) {
        printf("open log file %s , errno = %d\n", file, errno);
    }
}

int com_vprintf(const char* fun, com_log_module module, const char* fmt, ...)
{
    if (module >= COM_MODULE_MAX) {
        return -1;
    }

    int level = _infos[module].level;
    if (level < pri_level) {
        return -1;
    }

    const char* mod       = _infos[module].name_prefix;
    char*       level_str = "unknown";

    switch (level) {
    case COM_LOG_DEBUG:
        level_str = "DBG";
        break;
    case COM_LOG_INFO:
        level_str = "INF";
        break;
    case COM_LOG_ERROR:
        level_str = "ERR";
        break;
    default:
        break;
    }
    va_list va;
    va_start(va, fmt);
    int len = _com_vprintf(fun, mod, level_str, fmt, va);
    va_end(va);

    return len;
}
